lsとFreeBSD 10.4Rと11.2Rとlocaleとわたしたち
https://gyazo.com/df0a040684bb723403ff2754805b3d61
2018年11月9日(土) KOF2018
関西*BSDユーザ会研究会番外編
むとうたけし@関西*BSDユーザ会 (@610t) ことのおこり
電子メール from H先生@N高専 2018/10/16 14:19
FreeBSD 10.4Rから11.2Rに乗り換えたらlsの出力順序がちがう。原因を知らないか?
10.4Rは、LANGに関わらず文字コード順
AAA→BBB→aaa→bbb
11.2Rは、LANG=ja_JP.UTF-8の時は辞書順
aaa→AAA→bbb→BBB
code:10.4R
% LANG=C ls
AAA BBB aaa bbb
% LANG=ja_JP.UTF-8 ls
AAA BBB aaa bbb
code:11.2R
% LANG=C ls
AAA BBB aaa bbb
% LANG=ja_JP.UTF-8 ls
aaa AAA bbb BBB
ちなみに、12-CURRENTの場合
https://gyazo.com/040374afc5e7b834b1c3efc273a21772
LC_COLLATEが文字列ソート順に影響を与える
電子メール from K1@K*BUG 2018/10/17 07:48
文字列のソート順は LC_COLLATE環境変数が関わる
手元のメモでは、2016/11/19には既に変わっていた
そろそろ ja_JP.UTF-8 に移行しては?
facebook FreeBSD研究部に投稿
facebook FreeBSD研究部 2018/10/17 08:01
シェルスクリプトでは先頭でLANG=Cするのが定石、LC_COLLATE=Cで幸せ? by K2@K*BUG 2018/10/17 9:54
LC_COLLATE=CでOK by U 2018/10/17 17:09
UTF-8の場合、性能が著しく悪くなる場合がある by S 2018/10/17 23:44
ログインクラスでの設定
電子メール from K1@K*BUG 2018/10/17 10:14
ログインクラスの設定で、回避可能
1. /etc/master.passwd にログインクラス(第5フィールド)を設定する(ここでは foo とする)
2. /etc/login.conf に以下の行を追加
code:/etc/login.conf
foo:\
:lc_collate=C:\
:tc=default:
3. データベースを更新
# cap_mkdb /etc/login.conf
むとうの調査
*cmp関数で文字列ソート用の比較をしている
strcoll(3) を使っているものが多い
11.0にMFC(Merge From Current)されたのは、2016 /7/8 00:04:57 UTC
strcoll(3)を使う他のコマンド(sortなど)全てに影響がある
table:最近のFreeBSDリリース時期と今回の問題の関連
リリース 日時 備考
2018/10/16 H@N高専からの質問
11.2R 2018/6/27
10.4R 2017/10/3
11.1R 2017/7/26
2016/11/19 K1@K*BUGが気づく
11.0R 2016/10/10
2016/7/8 MFC to 11.0
10.3R 2016/4/4
2015/11/7 strcollの大きな変更
10.2R 2015/8/13
Revision 290494 Changelog
code:Changelog
Improve collation string and locales support
Merge collation support from Illumos and DragonflyBSD.
Locales are now generated with the new localedef(1) tool from CLDR POSIX files.
The generated files are now identified as "BSD 1.0" format.
The libc now only read "BSD 1.0" locales definitions, all other version will be
set to "C"
The localedef(1) tool has been imported from Illumos and modified to use tree(3)
instead of the CDDL avl(3)
A set of tool created by edwin@ and extended by marino@ for dragonfly has been
added to be able to generate locales and the Makefiles from the vanilla CLDR
unicode databases + a universal UTF-8 charmap (by marino@)
Update the locales to unicode v27
Given our regex(3) does not support multibyte (yet) it has been forced to always
use locale C
Remove now unused colldef(1) and mklocale(1)
Finish implementing the numeric BSD extension for ctypes
The number of supported locales has grown from 175 to 250 locales. Among the new
locales: 6 Arabic locales (AE EG JO MA QA SA), Different variations of spanish
locales.
Added new 3 components locales for mn_Cyrl_MN, sr_Cyrl_RS sr_Latn_RS,
zh_Hans_CN, zh_Hant_HK and zh_Hant_TW. Some aliases has been for 2 components
version when possible.
Thanks: Garrett D'Amore (Illumos) who made sure all his work was done under
BSD license!, Edwin Groothuis (edwin@) for the work he made on tools to be able
to generate locales definition usable in freebsd sources out of vanilla CLDR
definitions, John Marino (DragonflyBSD) who first merge the Illumos work into
Dragonfly and spent hours tracking down bugs.
Revision 290494の実際
strcmpで文字の順序をつけていた部分が、wcscollを使うように変わっている
https://gyazo.com/39b9a5bc133578b8590a957a298b0ed3
https://gyazo.com/8f9149ea1a9479ebd1c28d2a4acc6a86
https://gyazo.com/03631eef67a32990ebbd876d0372c268
パフォーマンスは本当に違う?
LC_COLLATEで本当にパフォーマンスが違うか簡単に試してみました
テストディレクトリにあるデータは以下の通り
code:shell
% LC_COLLATE=C ls
AA AB aa ab あ い ア イ
% LC_COLLATE=ja_JP.UTF-8 ls
aa AA ab AB あ ア い イ
以下のようなスクリプトで、LC_COLLATEを変えて、100000回lsを実行
code:ls_many_time.sh
LANG=$1
TIMES=$2
for i in jot ${TIMES} 1
do
LC_COLLATE=${LANG} ls 2>&1 > /dev/null
done
ザクっと、25%ぐらいCよりja_JP.UTF-8の方が遅い感じ
code:shell
% /usr/bin/time ../ls_many_time.sh ja_JP.UTF-8 100000
251.51 real 85.28 user 167.43 sys
% /usr/bin/time ../ls_many_time.sh C 100000
207.15 real 68.23 user 140.23 sys
グラフにしてみると1割ぐらいオーバーヘッドがある
code:ls_sum2.sh
DIGIT=20
for i in jot 100 10000 100000 10000
do
TIMES=${i}
(echo -n ${TIMES},; \
/usr/bin/time ../ls_many_time.sh C ${TIMES} 2>&1 |awk '{printf("%f,%f,%f,",$1,$3,$5)}'; \
/usr/bin/time ../ls_many_time.sh ja_JP.UTF-8 ${TIMES} 2>&1 |awk '{printf("%f,%f,%f\n",$1,$3,$5)}'; \
)
done
https://gyazo.com/a3d7a54c45376df477f41ab3a832787d
code:ls_summary.sh
DIGIT=17
TIMES=1
for i in jot ${DIGIT} 1
do
(echo -n ${TIMES},; \
/usr/bin/time ../ls_many_time.sh C ${TIMES} 2>&1 |awk '{printf("%f,%f,%f,",$1,$3,$5)}'; \
/usr/bin/time ../ls_many_time.sh ja_JP.UTF-8 ${TIMES} 2>&1 |awk '{printf("%f,%f,%f\n",$1,$3,$5)}'; \
)
TIMES=expr ${TIMES} \* 2
done
https://gyazo.com/83a20c2188f0f306ee0b7be776196969
おわりに
みなさまのお力で、意外と早く原因にたどり着けました
たかがlsの出力ですが、注意したいですね
シェルスクリプトでは、LANG, LC_ALL, LC_COLLATEなどを適切に設定しましょう